<!DOCTYPE html>
<html lang="en">
<head>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
    <meta charset="utf-8">
    <title>Webtyler</title>
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <link rel="preconnect" href="https://fonts.gstatic.com/">
    <link href="https://fonts.googleapis.com/css2?family=Roboto:wght@100&display=swap" rel="stylesheet"> 
    <link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300&display=swap" rel="stylesheet"> 
    <link rel="canonical" href="https://wareya.github.io/webtyler/">
<script>
'use strict';
window.onload = () =>
{
    // mildly-privacy-respecting analytics if running from github.io
    // because github.io is dumb and doesn't have *any* access analytics *at all*
    // if this bothers you, get an ad blocker
    if((window.location + "").startsWith("https://wareya.github.io/webtyler/"))
    {
        let script = document.createElement("script");
        script.dataset.goatcounter = "https://wareya.goatcounter.com/count";
        script.setAttribute("src", "https://gc.zgo.at/count.js");
        script.setAttribute("async", "");
        document.body.appendChild(script);
    }
    // https://stackoverflow.com/questions/9267899/arraybuffer-to-base64-encoded-string
    function _arrayToBase64(buffer) {
        let binary = '';
        let bytes = new Uint8Array(buffer);
        for (let i = 0; i < bytes.length; i++)
            binary += String.fromCharCode(bytes[i]);
        return window.btoa(binary);
    }
    // https://stackoverflow.com/questions/21797299/convert-base64-string-to-arraybuffer
    function _base64ToArray(base64)
    {
        let binary_string = window.atob(base64);
        let bytes = new Array(binary_string.length);
        for (let i = 0; i < binary_string.length; i++)
            bytes[i] = binary_string.charCodeAt(i);
        return bytes;
    }
    function enter(e)
    {
        e.stopPropagation();
        e.preventDefault();
        
        let dropzone = document.getElementById("dropzone");
        dropzone.style.opacity = 0.5;
    }
    function over(e)
    {
        e.stopPropagation();
        e.preventDefault();
        
        let dropzone = document.getElementById("dropzone");
        dropzone.style.opacity = 0.5;
    }
    function leave(e)
    {
        e.stopPropagation();
        e.preventDefault();
        
        let dropzone = document.getElementById("dropzone");
        dropzone.style.opacity = 1.0;
    }
    let img = undefined;
    
    let mode = "minitiles";
    
    let tileWidth = 16;
    let tileHeight = 16;
    let leftOffset = 0;
    let rightOffset = 0;
    let bottomOffset = 0;
    let topOffset = 0;
    
    let canvas = document.createElement('canvas');
    canvas.width = 192;
    canvas.height = 64;
    let previewcanvas = document.createElement('canvas');
    previewcanvas.width = 12*tileWidth;
    previewcanvas.height = 9*tileHeight;
    let rpgmakercanvas = document.createElement('canvas');
    rpgmakercanvas.width = 2*tileWidth;
    rpgmakercanvas.height = 3*tileHeight;
    let gms2canvas = document.createElement('canvas');
    gms2canvas.width = 12*tileWidth;
    gms2canvas.height = 4*tileHeight;

    function copyTile(img, ctx, to, from)
    {
        ctx.clearRect(
            to[0]*tileWidth, to[1]*tileHeight,
            tileWidth, tileHeight
        );
        ctx.drawImage(
            img,
            from[0]*tileWidth, from[1]*tileHeight,
            tileWidth, tileHeight,
            to[0]*tileWidth, to[1]*tileHeight,
            tileWidth, tileHeight
        );
    }

    function copyTileSectionRaw(img, ctx, target, section, data)
    {
        let x = target[0];
        let y = target[1];
        let offx1 = Math.floor(tileWidth/2) + leftOffset;
        let offx2 = offx1 - leftOffset + rightOffset;
        let offy1 = Math.floor(tileHeight/2) + topOffset;
        let offy2 = offy1 - topOffset + bottomOffset;
        let midwx = rightOffset - leftOffset;
        let midwy = bottomOffset - topOffset;
        let endwx = tileWidth - offx2;
        let endwy = tileHeight - offy2;
        
        let offset_x = [0, offx1, offx2][section[0]];
        let offset_y = [0, offy1, offy2][section[1]];
        let size_x = [offx1, midwx, endwx][section[0]];
        let size_y = [offy1, midwy, endwy][section[1]];
        ctx.clearRect(
            x*tileWidth+offset_x, y*tileHeight+offset_y,
            size_x, size_y
        );
        ctx.drawImage(
            img,
            data[0]*tileWidth+offset_x, data[1]*tileHeight+offset_y,
            size_x, size_y,
            x*tileWidth+offset_x, y*tileHeight+offset_y,
            size_x, size_y
        );
    }
    function copyTilePixels(img, ctx, target, source, from, to, size)
    {
        let x = target[0] * tileWidth + to[0];
        let y = target[1] * tileHeight + to[1];

        let source_x = source[0] * tileWidth + from[0];
        let source_y = source[1] * tileHeight + from[1];
        
        ctx.clearRect(
            x, y,
            size[0], size[1],
        );
        ctx.drawImage(
            img,
            source_x, source_y,
            size[0], size[1],
            x, y,
            size[0], size[1],
        );
    }

    function copyTileQuadRaw(img, ctx, target, section, data)
    {
        let x = target[0];
        let y = target[1];

        let offx1 = Math.floor(tileWidth/2) + leftOffset;
        let offx2 = offx1 - leftOffset + rightOffset;
        let offy1 = Math.floor(tileHeight/2) + topOffset;
        let offy2 = offy1 - topOffset + bottomOffset;
        let offx =  Math.floor(offx1/2 + offx2/2);
        let offy =  Math.floor(offy1/2 + offy2/2);
        let offset_x = [0, offx][section[0]];
        let offset_y = [0, offy][section[1]];
        let size_x = [offx, tileWidth - offx][section[0]];
        let size_y = [offy, tileHeight - offy][section[1]];

        ctx.clearRect(
            x*tileWidth+offset_x, y*tileHeight+offset_y,
            size_x, size_y
        );
        ctx.drawImage(
            img,
            data[0]*tileWidth+offset_x, data[1]*tileHeight+offset_y,
            size_x, size_y,
            x*tileWidth+offset_x, y*tileHeight+offset_y,
            size_x, size_y
        );
    }
    
    function copyTileSection(img, ctx, target, section, _data)
    {
        let data = _data[section[1]*3+section[0]];
        if(data[0] < 0 || data[1] < 0)
            return;
        copyTileSectionRaw(img, ctx, target, section, data);
    }
    
    function apply_subtile_data(img, ctx, data_array)
    {
        for(let i = 0; i < data_array.length; i++)
        {
            let target_tile = data_array[i][0];
            let data = data_array[i][1];
            for(let y = 0; y < 3; y++)
            {
                for(let x = 0; x < 3; x++)
                {
                    let section = [x, y];
                    copyTileSection(img, ctx, target_tile, section, data);
                }
            }
        }
    }
    function apply_tile_data(img, ctx, data_array)
    {
        for(let i = 0; i < data_array.length; i++)
        {
            let target_tile = data_array[i][0];
            let data = data_array[i][1];
            copyTile(img, ctx, target_tile, data);
        }
    }

    function updateMinitiles(img, ctx)
    {
        apply_subtile_data(img, ctx, minitiles_data);
    }

    function update4x4(img, ctx)
    {
        apply_tile_data(img, ctx, fourxfour_data);
    }

    function update3x3(img, ctx)
    {
        // convert 3x3 to 4x4
        let temp_canvas = document.createElement('canvas');
        temp_canvas.width = tileWidth*4;
        temp_canvas.height = tileHeight*4;
        let ctx2 = temp_canvas.getContext("2d");
        apply_subtile_data(img, ctx2, threexthree_data);
        // convert 4x4 to godot
        apply_tile_data(temp_canvas, ctx, fourxfour_data);
    }
    
    function fix_inner_corners(img, ctx, source_tile)
    {
        let data_array = inner_corners_data;
        for(let i = 0; i < data_array.length; i++)
        {
            let target_tile = data_array[i][0];
            let source_sections = data_array[i][1];
            for(let section of source_sections)
            {
                section = [section[0]*2, section[1]*2];
                copyTileSectionRaw(img, ctx, target_tile, section, source_tile);
            }
        }
    }

    function updatePreviews(img)
    {
        if(!img)
            return;
        canvas.width = 12*tileWidth;
        canvas.height = 4*tileHeight;
        let ctx = canvas.getContext("2d");
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        if(mode == "minitiles")
            updateMinitiles(img, ctx);
        if(mode == "basic")
        {
            // convert basic to minitiles
            let temp_canvas = document.createElement('canvas');
            temp_canvas.width = tileWidth*5;
            temp_canvas.height = tileHeight;
            let ctx2 = temp_canvas.getContext("2d");
            copyTile(img, ctx2, [0, 0], [0, 0])
            copyTile(img, ctx2, [1, 0], [1, 0])
            copyTile(img, ctx2, [2, 0], [1, 0])
            copyTile(img, ctx2, [3, 0], [1, 0])
            copyTile(img, ctx2, [4, 0], [1, 0])
            // convert minitiles to godot
            updateMinitiles(temp_canvas, ctx);
        }
        if(mode == "basicborder" || mode == "basicfullborder")
        {
            // convert basic to minitiles
            let temp_canvas = document.createElement('canvas');
            temp_canvas.width = tileWidth*5;
            temp_canvas.height = tileHeight;
            let ctx2 = temp_canvas.getContext("2d");
            copyTile(img, ctx2, [0, 0], [0, 0])
            copyTile(img, ctx2, [1, 0], [1, 0])
            copyTile(img, ctx2, [2, 0], [1, 0])
            copyTile(img, ctx2, [3, 0], [1, 0])
            copyTile(img, ctx2, [4, 0], [1, 0])
            // copy borders over
            let h = Math.floor(tileHeight/2);
            // sides
            {
                let o = Math.floor(topOffset/2 + bottomOffset/2);
                let a = 0;
                let b = Math.floor(tileHeight/4 + o);
                let c = Math.floor(tileHeight*3/4 + o);
                let d = tileHeight;
                // left border
                let w1 = Math.floor(tileWidth/2 + leftOffset);
                copyTilePixels(img, ctx2, [1, 0], [0, 0], [0, b    ], [0, b], [w1, c-b]);
                copyTilePixels(img, ctx2, [1, 0], [0, 0], [0, b    ], [0, c], [w1, d-c]);
                copyTilePixels(img, ctx2, [1, 0], [0, 0], [0, b+d-c], [0, 0], [w1, b  ]);
                // right border
                let w2 = Math.floor(tileWidth/2 - rightOffset);
                let z = tileWidth-w2;
                copyTilePixels(img, ctx2, [1, 0], [0, 0], [z, b    ], [z, b], [w2, c-b]);
                copyTilePixels(img, ctx2, [1, 0], [0, 0], [z, b    ], [z, c], [w2, d-c]);
                copyTilePixels(img, ctx2, [1, 0], [0, 0], [z, b+d-c], [z, 0], [w2, b  ]);
            }
            // top/bottom
            {
                let o = Math.floor(leftOffset/2 + rightOffset/2);
                let a = 0;
                let b = Math.floor(tileWidth/4 + o);
                let c = Math.floor(tileWidth*3/4 + o);
                let d = tileWidth;
                // left border
                let h1 = Math.floor(tileHeight/2 + topOffset);
                copyTilePixels(img, ctx2, [2, 0], [0, 0], [b    , 0], [b, 0], [c-b, h1]);
                copyTilePixels(img, ctx2, [2, 0], [0, 0], [b    , 0], [c, 0], [d-c, h1]);
                copyTilePixels(img, ctx2, [2, 0], [0, 0], [b+d-c, 0], [0, 0], [b  , h1]);
                // right border
                let h2 = Math.floor(tileHeight/2 - bottomOffset);
                let z = tileWidth-h2;
                copyTilePixels(img, ctx2, [2, 0], [0, 0], [b    , z], [b, z], [c-b, h2]);
                copyTilePixels(img, ctx2, [2, 0], [0, 0], [b    , z], [c, z], [d-c, h2]);
                copyTilePixels(img, ctx2, [2, 0], [0, 0], [b+d-c, z], [0, z], [b  , h2]);
            }
            if(mode == "basicfullborder")
            {
                copyTile(img, ctx2, [3, 0], [2, 0])
            }
            // convert minitiles to godot
            updateMinitiles(temp_canvas, ctx);
        }
        if(mode == "basiclongborder")
        {
            // convert basic to minitiles
            let temp_canvas = document.createElement('canvas');
            temp_canvas.width = tileWidth*5;
            temp_canvas.height = tileHeight;
            let ctx2 = temp_canvas.getContext("2d");
            copyTile(img, ctx2, [0, 0], [0, 0])
            copyTile(img, ctx2, [1, 0], [0, 0])
            copyTile(img, ctx2, [2, 0], [0, 0])
            copyTile(img, ctx2, [3, 0], [0, 0])
            copyTile(img, ctx2, [4, 0], [1, 0])
            // convert minitiles to godot
            updateMinitiles(temp_canvas, ctx);
        }
        if(mode == "4x4")
            update4x4(img, ctx);
        if(mode == "3x3")
            update3x3(img, ctx);
        if(mode == "4x4plus")
        {
            update4x4(img, ctx);
            fix_inner_corners(img, ctx, [4, 0]);
        }
        if(mode == "3x3plus")
        {
            update3x3(img, ctx);
            fix_inner_corners(img, ctx, [3, 0]);
        }
        if(mode == "5x3")
        {
            update3x3(img, ctx);
            fix_inner_corners(img, ctx, [4, 0]);

            copyTile(img, ctx, [0, 0], [3, 0])
            copyTile(img, ctx, [0, 2], [3, 1])

            copyTile(img, ctx, [0, 3], [4, 1])

            copyTile(img, ctx, [1, 3], [3, 2])
            copyTile(img, ctx, [3, 3], [4, 2])
        }
        let handle_5x2 = (img) =>
        {
            // convert 5x2 to 5x3
            let temp_canvas = document.createElement('canvas');
            temp_canvas.width = tileWidth*5;
            temp_canvas.height = tileHeight*3;
            let ctx2 = temp_canvas.getContext("2d");
            copyTile(img, ctx2, [4, 1], [3, 0])
            copyTile(img, ctx2, [4, 0], [4, 0])
            copyTile(img, ctx2, [3, 2], [3, 1])
            copyTile(img, ctx2, [4, 2], [4, 1])
            copyTile(img, ctx2, [3, 0], [2, 0])
            copyTile(img, ctx2, [3, 1], [2, 1])
            copyTile(img, ctx2, [0, 0], [0, 0])
            copyTile(img, ctx2, [0, 2], [0, 1])
            copyTile(img, ctx2, [2, 0], [1, 0])
            copyTile(img, ctx2, [2, 2], [1, 1])
            
            copyTileQuadRaw(img, ctx2, [1, 0], [0, 0], [4, 1])
            copyTileQuadRaw(img, ctx2, [1, 0], [1, 0], [3, 1])
            copyTileQuadRaw(img, ctx2, [1, 0], [0, 1], [1, 0])
            copyTileQuadRaw(img, ctx2, [1, 0], [1, 1], [0, 0])

            copyTileQuadRaw(img, ctx2, [1, 2], [0, 1], [4, 1])
            copyTileQuadRaw(img, ctx2, [1, 2], [1, 1], [3, 1])
            copyTileQuadRaw(img, ctx2, [1, 2], [0, 0], [1, 1])
            copyTileQuadRaw(img, ctx2, [1, 2], [1, 0], [0, 1])
            
            copyTileQuadRaw(img, ctx2, [0, 1], [0, 1], [2, 0])
            copyTileQuadRaw(img, ctx2, [0, 1], [0, 0], [2, 1])
            copyTileQuadRaw(img, ctx2, [0, 1], [1, 1], [0, 0])
            copyTileQuadRaw(img, ctx2, [0, 1], [1, 0], [0, 1])

            copyTileQuadRaw(img, ctx2, [2, 1], [1, 1], [2, 0])
            copyTileQuadRaw(img, ctx2, [2, 1], [1, 0], [2, 1])
            copyTileQuadRaw(img, ctx2, [2, 1], [0, 1], [1, 0])
            copyTileQuadRaw(img, ctx2, [2, 1], [0, 0], [1, 1])
            
            copyTileQuadRaw(img, ctx2, [1, 1], [1, 1], [0, 1-1])
            copyTileQuadRaw(img, ctx2, [1, 1], [0, 1], [1, 1-1])
            copyTileQuadRaw(img, ctx2, [1, 1], [1, 0], [0, 2-1])
            copyTileQuadRaw(img, ctx2, [1, 1], [0, 0], [1, 2-1])
            
            // handle 5x3
            update3x3(temp_canvas, ctx);
            fix_inner_corners(temp_canvas, ctx, [4, 0]);

            copyTile(temp_canvas, ctx, [0, 0], [3, 0])
            copyTile(temp_canvas, ctx, [0, 2], [3, 1])

            copyTile(temp_canvas, ctx, [0, 3], [4, 1])

            copyTile(temp_canvas, ctx, [1, 3], [3, 2])
            copyTile(temp_canvas, ctx, [3, 3], [4, 2])
        };
        if(mode == "5x2")
        {
            handle_5x2(img);
        }
        if(mode == "4x2")
        {
            // convert 4x2 to 5x2
            let temp_canvas = document.createElement('canvas');
            temp_canvas.width = tileWidth*5;
            temp_canvas.height = tileHeight*2;
            let ctx2 = temp_canvas.getContext("2d");
            
            copyTile(img, ctx2, [0, 0], [0, 0])
            copyTile(img, ctx2, [0, 1], [0, 1])
            copyTile(img, ctx2, [1, 0], [1, 0])
            copyTile(img, ctx2, [1, 1], [1, 1])
            
            copyTile(img, ctx2, [4, 0], [3, 0])
            copyTile(img, ctx2, [3, 0], [2, 0])
            
            copyTileQuadRaw(img, ctx2, [2, 0], [0, 0], [2, 0])
            copyTileQuadRaw(img, ctx2, [2, 0], [1, 0], [2, 0])
            copyTileQuadRaw(img, ctx2, [2, 0], [0, 1], [2, 1])
            copyTileQuadRaw(img, ctx2, [2, 0], [1, 1], [2, 1])
            
            copyTileQuadRaw(img, ctx2, [2, 1], [0, 0], [2, 1])
            copyTileQuadRaw(img, ctx2, [2, 1], [1, 0], [2, 1])
            copyTileQuadRaw(img, ctx2, [2, 1], [0, 1], [2, 0])
            copyTileQuadRaw(img, ctx2, [2, 1], [1, 1], [2, 0])
            
            copyTileQuadRaw(img, ctx2, [3, 1], [0, 0], [2, 0])
            copyTileQuadRaw(img, ctx2, [3, 1], [0, 1], [2, 0])
            copyTileQuadRaw(img, ctx2, [3, 1], [1, 0], [3, 1])
            copyTileQuadRaw(img, ctx2, [3, 1], [1, 1], [3, 1])
            
            copyTileQuadRaw(img, ctx2, [4, 1], [0, 0], [3, 1])
            copyTileQuadRaw(img, ctx2, [4, 1], [0, 1], [3, 1])
            copyTileQuadRaw(img, ctx2, [4, 1], [1, 0], [2, 0])
            copyTileQuadRaw(img, ctx2, [4, 1], [1, 1], [2, 0])
            
            handle_5x2(temp_canvas);
        }
        if(mode == "rpgmaker")
        {
            // convert rpgmaker to minitiles
            let temp_canvas = document.createElement('canvas');
            temp_canvas.width = tileWidth*5;
            temp_canvas.height = tileHeight;
            let ctx2 = temp_canvas.getContext("2d");
            // rpgmaker mv ignores the top left tile when actually tiling; it is essentailly a thumbnail
            copyTileQuadRaw(img, ctx2, [0, 0], [0, 0], [0, 1])
            copyTileQuadRaw(img, ctx2, [0, 0], [1, 0], [1, 1])
            copyTileQuadRaw(img, ctx2, [0, 0], [0, 1], [0, 2])
            copyTileQuadRaw(img, ctx2, [0, 0], [1, 1], [1, 2])
            
            copyTileQuadRaw(img, ctx2, [1, 0], [0, 1], [0, 1])
            copyTileQuadRaw(img, ctx2, [1, 0], [1, 1], [1, 1])
            copyTileQuadRaw(img, ctx2, [1, 0], [0, 0], [0, 2])
            copyTileQuadRaw(img, ctx2, [1, 0], [1, 0], [1, 2])
            
            copyTileQuadRaw(img, ctx2, [2, 0], [1, 0], [0, 1])
            copyTileQuadRaw(img, ctx2, [2, 0], [0, 0], [1, 1])
            copyTileQuadRaw(img, ctx2, [2, 0], [1, 1], [0, 2])
            copyTileQuadRaw(img, ctx2, [2, 0], [0, 1], [1, 2])
            
            copyTile(img, ctx2, [3, 0], [1, 0])
            
            copyTileQuadRaw(img, ctx2, [4, 0], [1, 1], [0, 1])
            copyTileQuadRaw(img, ctx2, [4, 0], [0, 1], [1, 1])
            copyTileQuadRaw(img, ctx2, [4, 0], [1, 0], [0, 2])
            copyTileQuadRaw(img, ctx2, [4, 0], [0, 0], [1, 2])
            // convert minitiles to godot
            updateMinitiles(temp_canvas, ctx);
            
        }
        let output = document.getElementById("output");
        output.src = canvas.toDataURL();

        if(canvas.width > 384)
        {
            output.classList.remove("pixelated_image");
            output.classList.add("smooth_image");
        }
        else
        {
            output.classList.remove("smooth_image");
            output.classList.add("pixelated_image");
        }
        
        output.onload = () => {
            // simple enough we can do it inline
            rpgmakercanvas.width = 2*tileWidth;
            rpgmakercanvas.height = 3*tileHeight;
            ctx = rpgmakercanvas.getContext("2d");
            ctx.clearRect(0, 0, rpgmakercanvas.width, rpgmakercanvas.height);
            
            copyTile(output, ctx, [0, 0], [0, 3]);
            copyTile(output, ctx, [1, 0], [2, 1]);
            copyTile(output, ctx, [0, 1], [8, 0]);
            copyTile(output, ctx, [1, 1], [11, 0]);
            copyTile(output, ctx, [0, 2], [8, 3]);
            copyTile(output, ctx, [1, 2], [11, 3]);
            
            let rpgmakeroutput = document.getElementById("rpgmaker");
            rpgmakeroutput.src = rpgmakercanvas.toDataURL();
            
            if(rpgmakercanvas.height > 96)
            {
                rpgmakeroutput.classList.remove("pixelated_image");
                rpgmakeroutput.classList.add("smooth_image");
            }
            else
            {
                rpgmakeroutput.classList.remove("smooth_image");
                rpgmakeroutput.classList.add("pixelated_image");
            }
            
            gms2canvas.width = 12*tileWidth;
            gms2canvas.height = 4*tileHeight;
            ctx = gms2canvas.getContext("2d");
            ctx.clearRect(0, 0, gms2canvas.width, gms2canvas.height);
            for(let i = 0; i < godot_to_gms.length; i++)
            {
                let godot = [i%12, Math.floor(i/12)];
                let j = godot_to_gms[i];//+1;
                if(j <= 0)
                    continue;
                let gms = [j%12, Math.floor(j/12)];
                copyTile(output, ctx, gms, godot);
                //copyTile(output, ctx, godot, gms);
            }
            let gms2output = document.getElementById("gms2");
            gms2output.src = gms2canvas.toDataURL();
            
            if(gms2canvas.height > 64)
            {
                gms2output.classList.remove("pixelated_image");
                gms2output.classList.add("smooth_image");
            }
            else
            {
                gms2output.classList.remove("smooth_image");
                gms2output.classList.add("pixelated_image");
            }
            
            previewcanvas.width = 12*tileWidth;
            previewcanvas.height = 9*tileHeight;
            ctx = previewcanvas.getContext("2d");
            ctx.clearRect(0, 0, previewcanvas.width, previewcanvas.height);
            for(let y = 0; y < preview_data.length; y++)
            {
                let scanline = preview_data[y];
                for(let x = 0; x < scanline.length; x++)
                {
                    let source = scanline[x];
                    if(source < 0)
                        continue;
                    if(source >= 22)
                        source += 1;
                    let from = [source%12, Math.floor(source/12)];
                    copyTile(output, ctx, [x, y], from);
                }
            }
            let preview = document.getElementById("preview");
            preview.src = previewcanvas.toDataURL();

            if(previewcanvas.width > 384)
            {
                preview.classList.remove("pixelated_image");
                preview.classList.add("smooth_image");
            }
            else
            {
                preview.classList.remove("smooth_image");
                preview.classList.add("pixelated_image");
            }
        };
    }

    function delete_color_correction_metadata(data)
    {
        let gamma_chunk = [0x00, 0x00, 0x00, 0x04, 0x67, 0x41, 0x4D, 0x41];
        let srgb_chunk = [0x00, 0x00, 0x00, 0x01, 0x73, 0x52, 0x47, 0x42];
        //let srgb_chunk  = new Array([0x00, 0x00, 0x00, 0x04, 0x67, 0x41, 0x4D, 0x41]);
        function find(array)
        {
            return data.findIndex((_, i, data) =>
            {
                function equal(buf1, buf2)
                {
                    if (buf1.length != buf2.length)
                        return false;
                    for (let i = 0 ; i != buf1.length ; i++)
                    {
                        if (buf1[i] != buf2[i])
                            return false;
                    }
                    return true;
                }
                let asdf = equal(data.slice(i, i+8), array); // gAMA chunk
                return asdf;
            });
        };
        let index = find(gamma_chunk);
        if(index >= 0)
            data.splice(index, 16);
        index = find(srgb_chunk);
        if(index >= 0)
            data.splice(index, 13);
        return data;
    }
    
    function load_image(img, src, mime)
    {
        let dropzone = document.getElementById("dropzone");

        img.onload = (e) =>
        {
            dropzone.style.backgroundImage = "url('"+img.src + "')";
            if(img.width > 300 || img.height > 200)
                dropzone.style.imageRendering = "auto";
            else
                dropzone.style.imageRendering = "crisp-edges";
            updatePreviews(img);
        };
        if(mime.includes("png") && src.includes("base64,"))
        {
            let data = _base64ToArray(src.split("base64,")[1]);
            data = delete_color_correction_metadata(data);
            data = _arrayToBase64(data);
            src = "data:image/png;base64," + data;
        }
        img.src = src;
    }
    
    function drop(e)
    {
        e.stopPropagation();
        e.preventDefault();
        
        let dropzone = document.getElementById("dropzone");
        dropzone.style.opacity = 1.0;
        
        const dt = e.dataTransfer;
        let files = dt.files;
        
        for (let i = 0; i < files.length; i++)
        {
            const file = files[i];
            
            if (!file.type.startsWith('image/')){ continue; }
            
            img = new Image();
            const reader = new FileReader();
            reader.onload = (e) =>
            {
                load_image(img, e.target.result, file.type);
            };
            reader.readAsDataURL(file);
        }
    }
    
    let dropzone = document.getElementById("dropzone");
    dropzone.ondragenter = enter;
    dropzone.ondragleave = leave;
    dropzone.ondragover = over;
    dropzone.ondrop = drop;

    dropzone.onclick = (e) =>
    {
        let input = document.createElement("input");
        input.type = "file";
        input.onchange = (e) =>
        {
            // getting a hold of the file reference
            for(let file of e.target.files)
            {
                if (!file.type.startsWith('image/')){ continue; }
                
                img = new Image();
                const reader = new FileReader();
                reader.onload = (e) =>
                {
                    load_image(img, e.target.result, file.type);
                };
                reader.readAsDataURL(file);
                break;
            }
        }

        input.click();
    };
    
    let option_basic = document.getElementById("option_basic");
    let option_basicborder = document.getElementById("option_basicborder");
    let option_basicfullborder = document.getElementById("option_basicfullborder");
    let option_basiclongborder = document.getElementById("option_basiclongborder");
    let option_minitiles = document.getElementById("option_minitiles");
    let option_4x4 = document.getElementById("option_4x4");
    let option_3x3 = document.getElementById("option_3x3");
    let option_4x4plus = document.getElementById("option_4x4plus");
    let option_3x3plus = document.getElementById("option_3x3plus");
    let option_5x3 = document.getElementById("option_5x3");
    let option_5x2 = document.getElementById("option_5x2");
    let option_4x2 = document.getElementById("option_4x2");
    let option_rpgmaker = document.getElementById("option_rpgmaker");
    function reset_selected()
    {
        option_basic.classList.remove("selected");
        option_basicborder.classList.remove("selected");
        option_basicfullborder.classList.remove("selected");
        option_basiclongborder.classList.remove("selected");
        option_minitiles.classList.remove("selected");
        option_4x4.classList.remove("selected");
        option_3x3.classList.remove("selected");
        option_4x4plus.classList.remove("selected");
        option_3x3plus.classList.remove("selected");
        option_5x3.classList.remove("selected");
        option_5x2.classList.remove("selected");
        option_4x2.classList.remove("selected");
        option_rpgmaker.classList.remove("selected");
    };
    option_basic.onclick = () =>
    {
        mode = "basic";
        reset_selected();
        option_basic.classList.add("selected");
        updatePreviews(img);
    };
    option_basicborder.onclick = () =>
    {
        mode = "basicborder";
        reset_selected();
        option_basicborder.classList.add("selected");
        updatePreviews(img);
    };
    option_basicfullborder.onclick = () =>
    {
        mode = "basicfullborder";
        reset_selected();
        option_basicfullborder.classList.add("selected");
        updatePreviews(img);
    };
    option_basiclongborder.onclick = () =>
    {
        mode = "basiclongborder";
        reset_selected();
        option_basiclongborder.classList.add("selected");
        updatePreviews(img);
    };
    option_minitiles.onclick = () =>
    {
        mode = "minitiles";
        reset_selected();
        option_minitiles.classList.add("selected");
        updatePreviews(img);
    };
    option_4x4.onclick = () =>
    {
        mode = "4x4";
        reset_selected();
        option_4x4.classList.add("selected");
        updatePreviews(img);
    };
    option_3x3.onclick = () =>
    {
        mode = "3x3";
        reset_selected();
        option_3x3.classList.add("selected");
        updatePreviews(img);
    };
    option_4x4plus.onclick = () =>
    {
        mode = "4x4plus";
        reset_selected();
        option_4x4plus.classList.add("selected");
        updatePreviews(img);
    };
    option_3x3plus.onclick = () =>
    {
        mode = "3x3plus";
        reset_selected();
        option_3x3plus.classList.add("selected");
        updatePreviews(img);
    };
    option_5x3.onclick = () =>
    {
        mode = "5x3";
        reset_selected();
        option_5x3.classList.add("selected");
        updatePreviews(img);
    };
    option_5x2.onclick = () =>
    {
        mode = "5x2";
        reset_selected();
        option_5x2.classList.add("selected");
        updatePreviews(img);
    };
    option_4x2.onclick = () =>
    {
        mode = "4x2";
        reset_selected();
        option_4x2.classList.add("selected");
        updatePreviews(img);
    };
    option_rpgmaker.onclick = () =>
    {
        mode = "rpgmaker";
        reset_selected();
        option_rpgmaker.classList.add("selected");
        updatePreviews(img);
    };
    // https://stackoverflow.com/questions/6333814/how-does-the-paste-image-from-clipboard-functionality-work-in-gmail-and-google-c
    document.onpaste = (e) =>
    {
        let clip = (e.clipboardData || e.originalEvent.clipboardData);
        let items = clip.items;
        let files = clip.files;
        let types = clip.types;
        console.log(clip);
        console.log("items ----");
        for(let item of items)
        {
            console.log(item);
        }
        console.log("files ----");
        for(let item of files)
        {
            console.log(item);
        }
        console.log("typse ----");
        for(let item of types)
        {
            console.log(item);
            console.log(clip.getData(item));
        }
        for (let file of files)
        {
            if (!file.type.startsWith('image/')){ continue; }

            img = new Image();
            const reader = new FileReader();
            reader.onload = (e) =>
            {
                load_image(img, e.target.result, file.type);
            };
            reader.readAsDataURL(file);
        }
    };
    
    let input_width = document.getElementById("input_width");
    let input_height = document.getElementById("input_height");
    let input_left_offset = document.getElementById("input_left_offset");
    let input_right_offset = document.getElementById("input_right_offset");
    let input_top_offset = document.getElementById("input_top_offset");
    let input_bottom_offset = document.getElementById("input_bottom_offset");
    
    input_width.value = 16;
    input_height.value = 16;
    input_left_offset.value = 0;
    input_right_offset.value = 0;
    input_top_offset.value = 0;
    input_bottom_offset.value = 0;

    function checkInputs()
    {
        if(leftOffset < -Math.floor(tileWidth/2))
        {
            leftOffset = -Math.floor(tileWidth/2);
            input_left_offset.value = leftOffset;
        }
        if(leftOffset > tileWidth - Math.floor(tileWidth/2))
        {
            leftOffset = tileWidth - Math.floor(tileWidth/2);
            input_left_offset.value = leftOffset;
        }
        if(rightOffset < -Math.floor(tileWidth/2))
        {
            rightOffset = -Math.floor(tileWidth/2);
            input_right_offset.value = rightOffset;
        }
        if(rightOffset > tileWidth - Math.floor(tileWidth/2))
        {
            rightOffset = tileWidth - Math.floor(tileWidth/2);
            input_right_offset.value = rightOffset;
        }
        if(topOffset < -Math.floor(tileHeight/2))
        {
            topOffset = -Math.floor(tileHeight/2);
            input_top_offset.value = topOffset;
        }
        if(topOffset > tileHeight - Math.floor(tileHeight/2))
        {
            topOffset = tileHeight - Math.floor(tileHeight/2);
            input_top_offset.value = topOffset;
        }
        if(bottomOffset < -Math.floor(tileHeight/2))
        {
            bottomOffset = -Math.floor(tileHeight/2);
            input_bottom_offset.value = bottomOffset;
        }
        if(bottomOffset > tileHeight - Math.floor(tileHeight/2))
        {
            bottomOffset = tileHeight - Math.floor(tileHeight/2);
            input_bottom_offset.value = bottomOffset;
        }
    }
    
    input_width.oninput = (e) =>
    {
        tileWidth = parseInt(e.target.value);
        checkInputs();
        updatePreviews(img);
    };
    input_height.oninput = (e) =>
    {
        tileHeight = parseInt(e.target.value);
        checkInputs();
        updatePreviews(img);
    };
    input_left_offset.oninput = (e) =>
    {
        leftOffset = parseInt(e.target.value);
        checkInputs();
        if(leftOffset > rightOffset)
        {
            rightOffset = leftOffset;
            input_right_offset.value = e.target.value;
        }
        updatePreviews(img);
    };
    input_right_offset.oninput = (e) =>
    {
        rightOffset = parseInt(e.target.value);
        checkInputs();
        if(leftOffset > rightOffset)
        {
            leftOffset = rightOffset;
            input_left_offset.value = e.target.value;
        }
        updatePreviews(img);
    };
    input_top_offset.oninput = (e) =>
    {
        topOffset = parseInt(e.target.value);
        checkInputs();
        if(topOffset > bottomOffset)
        {
            bottomOffset = topOffset;
            input_bottom_offset.value = e.target.value;
        }
        updatePreviews(img);
    };
    input_bottom_offset.oninput = (e) =>
    {
        bottomOffset = parseInt(e.target.value);
        checkInputs();
        if(topOffset > bottomOffset)
        {
            topOffset = bottomOffset;
            input_top_offset.value = e.target.value;
        }
        updatePreviews(img);
    };
}
</script>
</head>

<body>
    <a href="https://github.com/wareya/webtyler/" target=_blank style="float: right; position: absolute; text-shadow: none; font-family: Roboto; font-weight: 300; right: 25px;">Github</a>
    <div id="app" class="affect">
        <div id="options" style="min-height: 10px;" class="affect">
            <p style="margin-top: 5px;">Modes</p>
            <div class="modes">
            <div id="option_basic" class="option affect"><span class="basicbg">Basic</span></div>
            <div id="option_basicborder" class="option affect"><span class="basicborderbg">Basic Border</span></div>
            <div id="option_basicfullborder" class="option affect"><span class="basicfullborderbg">Basic Full Border</span></div>
            <div id="option_basiclongborder" class="option affect"><span class="basiclongborderbg">Basic Long Border</span></div>
            <div id="option_minitiles" class="option affect selected"><span class="minitilesbg">Minitiles</span></div>
            <div id="option_4x4" class="option affect"><span class="fourxfourbg">4x4</span></div>
            <div id="option_4x4plus" class="option affect"><span class="fourxfourplusbg">4x4plus</span></div>
            <div id="option_3x3" class="option affect"><span class="threexthreebg">3x3</span></div>
            <div id="option_3x3plus" class="option affect"><span class="threexthreeplusbg">3x3plus</span></div>
            <div id="option_5x3" class="option affect"><span class="fivexthreebg">5x3</span></div>
            <div id="option_5x2" class="option affect"><span class="fivextwobg">5x2</span></div>
            <div id="option_4x2" class="option affect"><span class="fourxtwobg">4x2</span></div>
            <div id="option_rpgmaker" class="option affect"><span class="rpgmakerbg">RPG Maker</span></div>
            </div>
            <!-- <div id="option_godot" class="option affect"><span class="godot">Godot</span></div> -->
        </div>
        <div style="margin: 5px;">
            <p style="margin-top: 5px;">Webtyler</p>
            <div id="dropzoneWrapper">
                <div id="dropzone" class="noselect affect" style="opacity: 1; background-image: url(&quot;
                                                                  nWfv9x/CGnOTyyjKNgZz7tfqTdBf4AEvJoIEwvG90GaTzGHD8zrlmbZfzLpLiZyWLP3VhtHLZsl1wAdBFIX38o+QSnxEbAV3AeOx8+5SjjiTfcZBpbykT0599s7y50lgvfyqg+Y7DTzbt7YN5fsdhnPYOtGH46+K74rpYD3/9DTSdak0ib9Imvvv8bf+qJvKf2vlnCoh/n40IFXBbz3Z0QzK4DoJ5fL9ezL70fgMyvCf+8hYyr58v1ESujF2lweDRUyEO4YKLB1+AJjI+MU66Cy4WQBOJOrL3M6a92B5ra/Tu7o01O0YOJOUFuPwlVMA6ENbyC5AFJMWf3PEjP48LVOoPgCVePDNNPdgAAAAASUVORK5CYII=&quot;); image-rendering: crisp-edges;"><span>Drop Image File Here<br>(Or Paste Image)</span></div>
            </div>
            <div id="actualoptions">
                <div class="affect actualoptionsjustoptions">
                    <p>Options</p>
                    <div class="inputfuckery">
                        <div class="dummy"></div>
                        <label>Width</label>
                        <input id="input_width" type="number" value="16" step="1" min="2">
                    </div>
                    <div class="inputfuckery">
                        <div class="dummy"></div>
                        <label>Height</label>
                        <input id="input_height" type="number" value="16" step="1" min="2">
                    </div>
                    <div class="inputfuckery">
                        <div class="dummy"></div>
                        <label>Left Margin Offset</label>
                        <input id="input_left_offset" type="number" value="0" step="1">
                    </div>
                    <div class="inputfuckery">
                        <div class="dummy"></div>
                        <label>Right Margin Offset</label>
                        <input id="input_right_offset" type="number" value="0" step="1">
                    </div>
                    <div class="inputfuckery">
                        <div class="dummy"></div>
                        <label>Top Margin Offset</label>
                        <input id="input_top_offset" type="number" value="0" step="1">
                    </div>
                    <div class="inputfuckery">
                        <div class="dummy"></div>
                        <label>Bottom Margin Offset</label>
                        <input id="input_bottom_offset" type="number" value="0" step="1">
                    </div>
                </div>
                <p class="smol">Q: <i>Help! I pasted an image from an image editor, but<br>transparency isn't working, or all the pixels are shifted!</i></p>
                <p class="smol notop">A: Try a different image editor or a different browser<br>(some combinations are broken), or drop a file instead.</p>
                <p class="smol">Q: <i>Help! My colors are all messed up!</i></p>
                <p class="smol notop">A: Color profile data is stripped from PNGs for<br>technical reasons. Pasting can mess up colors too.</p>
                <p class="smol">Q: <i>What are these margin offset things?</i></p>
                <p class="smol notop">A: They control where tile corners/edges are sliced.</p>
                <p class="smol">Q: <i>I'm using RPG Maker, but the preview is wrong!</i></p>
                <p class="smol notop">A: Unlike Godot, RPG Maker can't distinguish between<br>corners and tips, so tips are made up of corner parts.</p>
                <p class="smol">Q: <i>Do you have any example inputs?</i></p>
                <p class="smol notop">A: <a href="examples.html" target=_blank>Yes (this is a link).</a></p>
            </div>
        </div>
        <div id="previews" class="affect" style="flex-grow: 1;">
            <p style="margin-top: 5px;">Godot</p>
            <img id="output" src="" class="pixelated_image">
            <p class="smol"><i>Tip: Right Click -&gt; Save Image As...</i></p>
            
            <div style="display:flex; flex-direction:row; margin-top: -8px; width: 384px;">
            <div style="flex: 1; width: 35%"><p>RPG Maker</p>
            <img style="max-width: 95%;" id="rpgmaker" src="" class="pixelated_image"></div>
            <div style="flex: 2; width: 65%"><p>GameMaker Studio 2 (47)</p>
            <img style="max-width: 95%; height:64px;" id="gms2" src="" class="pixelated_image"></div>
            </div>
            
            <p>Preview</p>
            <img id="preview" src="" class="pixelated_image">
        </div>
        <style type="text/css" scoped="">
a {
    text-decoration: none;
    color: rgba(64,64,255,1);
    text-shadow: 0px 0px 1px rgba(64,64,255,1);
}
.smol {
    font-size: 12px;
    font-weight: 300;
    width: 100%;
    max-width: 350px;
    margin: 10px auto;
    text-align: center;
}
p.notop {
    margin-top: -5px;
}
p {
    text-align: center;
    font-size: 20px;
    line-height: 1;
    margin: 10px 0;
}
h1, h2, h3, h4, h5, h6 {
    font-family: 'Roboto', sans;
    font-weight: 100;
    text-align: center;
    margin: 0.5em 0;
    padding-bottom: 0;
    line-height: 1;
}
body {
    font-weight: 100;
    background-color: rgb(0, 0, 0, 0.1);
}
img {
    min-width: 5px;
    min-height: 5px;
    
    box-shadow: 0 0 5px rgba(0,0,0,0.25);
}
label {
    font-weight: 300;
}
.inputfuckery {
    display: flex;
    flex-direction: row;
    box-sizing: padding-box;
}
.inputfuckery * {
    margin: 2px 5px;
}
.dummy {
    display: inline-block;
    flex-grow: 1;
}
input {
    border: 1px solid rgba(0,0,0,0.25);
    border-radius: 4px;
    text-align: right;
    width: 90px;
}
#actualoptions {
    font-size: 14px;
}
.actualoptionsjustoptions p {
    display: inline-block;
    float: left;
    margin-left: 15px;
}
p {
    font-weight: 300;
}
#options {
    font-weight: 300;
}
#output {
    object-fit: contain;
    width: 100%;
    max-width: 384px;
    height: 128px;
}
#preview {
    object-fit: contain;
    width: 100%;
    max-width: 384px;
    height: 288px;
}
#rpgmaker {
    display: block;
    margin: auto;

    object-fit: contain;
    min-width: 64px;
    max-width: 384px;
    height: 96px;
}
#gms2 {
    display: block;
    margin: auto;

    object-fit: contain;
    min-width: 64px;
    max-width: 384px;
    height: 96px;
}
div.affect {
    background-color: white;
    box-shadow: 0 0 10px rgba(0,0,0,0.25) inset;
    border-radius: 8px;
    margin: 5px;
    padding: 5px;
}
div.option {
    box-shadow: 0 0 10px rgba(0,0,0,0.25);
}
#app {
    font-family: 'Roboto', sans;
    display: flex;
    flex-direction: row;
    align-items: flex-start;
    width: 975px;
    height: 680px;
    margin: auto;
    border: 1px solid rgba(0,0,0,0.);
    border-radius: 6px;
    box-shadow: 0 0 20px rgba(0,0,0,0.5);
    padding: 5px;
    margin-top: 15px;
    z-index: -3;
}
#dropzoneWrapper {
    border: 2px dashed rgba(0,128,256,1);
    border-radius: 8px;
}
#dropzone {
    display: flex;
    align-items: center;
    justify-content: center;
    
    background-repeat: no-repeat;
    background-size: contain;
    background-position: center;
    
    padding: 0;
    position: relative;
    width: 300px;
    height: 200px;
    background-color: transparent;
    border: 1px solid white;
    box-sizing: border-box;
    position: relative;
    
    margin: 0;
    text-align: center;
    font-size: 30px;
    font-weight: 0;
    color: white;
    text-shadow: 0px 1px rgba(0, 0, 0, 0.65), 1px 1px rgba(0, 0, 0, 0.65);
    
    image-rendering: pixelated;
    image-rendering: crisp-edges;
}
.modes {
    flex-wrap: wrap;
    display: flex;
    flex-direction: row;
}
.option {
    width: 96px;
    height: 64px;
    box-sizing: content-box;
    user-select: none;
    text-align: center;
    vertical-align: middle;
    font-size: 16px;
    font-weight: 0;
    color: white;
    text-shadow: 0px 1px rgba(0, 0, 0, 0.65), 1px 1px rgba(0, 0, 0, 0.65);
}
.option:hover {
    opacity: 0.75;
}
div.selected {
    background-color: rgb(128, 192, 255, 0.25);
}
.noselect {
    -webkit-touch-callout: none;
    -webkit-user-select: none;
    -khtml-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
}
.minitilesbg {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 100%;
    width: 100%;
    image-rendering: pixelated;
    image-rendering: crisp-edges;
    background-repeat: no-repeat;
    background-size: contain;
    background-position: center;
    background-image: url('');
}
.basicbg {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 100%;
    width: 100%;
    image-rendering: pixelated;
    image-rendering: crisp-edges;
    background-repeat: no-repeat;
    background-size: contain;
    background-position: center;
    background-image: url("");
}
.basicborderbg {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 100%;
    width: 100%;
    image-rendering: pixelated;
    image-rendering: crisp-edges;
    background-repeat: no-repeat;
    background-size: contain;
    background-position: center;
    background-image: url("");
}
.basicfullborderbg {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 100%;
    width: 100%;
    image-rendering: pixelated;
    image-rendering: crisp-edges;
    background-repeat: no-repeat;
    background-size: contain;
    background-position: center;
    background-image: url("");
}
.basiclongborderbg {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 100%;
    width: 100%;
    image-rendering: pixelated;
    image-rendering: crisp-edges;
    background-repeat: no-repeat;
    background-size: contain;
    background-position: center;
    background-image: url("");
}
.fourxfourbg {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 100%;
    width: 100%;
    image-rendering: pixelated;
    image-rendering: crisp-edges;
    background-repeat: no-repeat;
    background-size: contain;
    background-position: center;
    background-image: url("");
}
.threexthreebg {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 100%;
    width: 100%;
    image-rendering: pixelated;
    image-rendering: crisp-edges;
    background-repeat: no-repeat;
    background-size: contain;
    background-position: center;
    background-image: url("");
}
.fivexthreebg {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 100%;
    width: 100%;
    image-rendering: pixelated;
    image-rendering: crisp-edges;
    background-repeat: no-repeat;
    background-size: contain;
    background-position: center;
    background-image: url("");
}
.fivextwobg {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 100%;
    width: 100%;
    image-rendering: pixelated;
    image-rendering: crisp-edges;
    background-repeat: no-repeat;
    background-size: contain;
    background-position: center;
    background-image: url("");
}
.fourxtwobg {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 100%;
    width: 100%;
    image-rendering: pixelated;
    image-rendering: crisp-edges;
    background-repeat: no-repeat;
    background-size: contain;
    background-position: center;
    background-image: url("");
}
.fourxfourplusbg {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 100%;
    width: 100%;
    image-rendering: pixelated;
    image-rendering: crisp-edges;
    background-repeat: no-repeat;
    background-size: contain;
    background-position: center;
    background-image: url("");
    
}
.threexthreeplusbg {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 100%;
    width: 100%;
    image-rendering: pixelated;
    image-rendering: crisp-edges;
    background-repeat: no-repeat;
    background-size: contain;
    background-position: center;
    background-image: url("");
}
.rpgmakerbg {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 100%;
    width: 100%;
    image-rendering: pixelated;
    image-rendering: crisp-edges;
    background-repeat: no-repeat;
    background-size: contain;
    background-position: center;
    background-image: url("");
}
.godotbg {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 100%;
    width: 100%;
    image-rendering: pixelated;
    image-rendering: crisp-edges;
    background-repeat: no-repeat;
    background-size: contain;
    background-position: center;
}
.smooth_image {
    image-rendering: auto;
}
.pixelated_image {
    image-rendering: crisp-edges;
    image-rendering: pixelated;
}
        </style>
    </div>
<script>
// convert minitiles to godot
var minitiles_data = [
    [[0,0], [[0,0],[0,0],[0,0],[1,0],[1,0],[1,0],[1,0],[1,0],[1,0],]],
    [[1,0], [[0,0],[0,0],[2,0],[0,0],[0,0],[2,0],[1,0],[1,0],[3,0],]],
    [[2,0], [[2,0],[2,0],[2,0],[2,0],[2,0],[2,0],[3,0],[3,0],[3,0],]],
    [[3,0], [[2,0],[0,0],[0,0],[2,0],[0,0],[0,0],[3,0],[1,0],[1,0],]],
    [[4,0], [[4,0],[4,0],[3,0],[4,0],[4,0],[3,0],[3,0],[3,0],[3,0],]],
    [[5,0], [[2,0],[2,0],[2,0],[2,0],[4,0],[4,0],[3,0],[4,0],[4,0],]],
    [[6,0], [[2,0],[2,0],[2,0],[4,0],[4,0],[2,0],[4,0],[4,0],[3,0],]],
    [[7,0], [[3,0],[4,0],[4,0],[3,0],[4,0],[4,0],[3,0],[3,0],[3,0],]],
    [[8,0], [[0,0],[0,0],[2,0],[0,0],[4,0],[4,0],[1,0],[4,0],[4,0],]],
    [[9,0], [[3,0],[3,0],[3,0],[4,0],[4,0],[4,0],[4,0],[4,0],[4,0],]],
    [[10,0], [[2,0],[2,0],[2,0],[4,0],[4,0],[4,0],[4,0],[4,0],[4,0],]],
    [[11,0], [[2,0],[0,0],[0,0],[4,0],[4,0],[0,0],[4,0],[4,0],[1,0],]],
    
    [[0,1], [[1,0],[1,0],[1,0],[1,0],[1,0],[1,0],[1,0],[1,0],[1,0],]],
    [[1,1], [[1,0],[1,0],[3,0],[1,0],[1,0],[3,0],[1,0],[1,0],[3,0],]],
    [[2,1], [[3,0],[3,0],[3,0],[3,0],[3,0],[3,0],[3,0],[3,0],[3,0],]],
    [[3,1], [[3,0],[1,0],[1,0],[3,0],[1,0],[1,0],[3,0],[1,0],[1,0],]],
    [[4,1], [[1,0],[1,0],[3,0],[1,0],[4,0],[4,0],[1,0],[4,0],[4,0],]],
    [[5,1], [[3,0],[4,0],[4,0],[4,0],[4,0],[4,0],[4,0],[4,0],[4,0],]],
    [[6,1], [[4,0],[4,0],[3,0],[4,0],[4,0],[4,0],[4,0],[4,0],[4,0],]],
    [[7,1], [[3,0],[1,0],[1,0],[4,0],[4,0],[1,0],[4,0],[4,0],[1,0],]],
    [[8,1], [[1,0],[4,0],[4,0],[1,0],[4,0],[4,0],[1,0],[4,0],[4,0],]],
    [[9,1], [[3,0],[4,0],[4,0],[4,0],[4,0],[4,0],[4,0],[4,0],[3,0],]],
    [[10,1], [[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],[-1,-1],]],
    
    [[11,1], [[4,0],[4,0],[3,0],[4,0],[4,0],[3,0],[4,0],[4,0],[3,0],]],
    [[0,2], [[1,0],[1,0],[1,0],[1,0],[1,0],[1,0],[0,0],[0,0],[0,0],]],
    [[1,2], [[1,0],[1,0],[3,0],[0,0],[0,0],[2,0],[0,0],[0,0],[2,0],]],
    [[2,2], [[3,0],[3,0],[3,0],[2,0],[2,0],[2,0],[2,0],[2,0],[2,0],]],
    [[3,2], [[3,0],[1,0],[1,0],[2,0],[0,0],[0,0],[2,0],[0,0],[0,0],]],
    [[4,2], [[1,0],[4,0],[4,0],[1,0],[4,0],[4,0],[1,0],[1,0],[3,0],]],
    [[5,2], [[4,0],[4,0],[4,0],[4,0],[4,0],[4,0],[3,0],[4,0],[4,0],]],
    [[6,2], [[4,0],[4,0],[4,0],[4,0],[4,0],[4,0],[4,0],[4,0],[3,0],]],
    [[7,2], [[4,0],[4,0],[1,0],[4,0],[4,0],[1,0],[3,0],[1,0],[1,0],]],
    [[8,2], [[3,0],[4,0],[4,0],[3,0],[4,0],[4,0],[3,0],[4,0],[4,0],]],
    [[9,2], [[4,0],[4,0],[4,0],[4,0],[4,0],[4,0],[4,0],[4,0],[4,0],]],
    [[10,2], [[4,0],[4,0],[3,0],[4,0],[4,0],[4,0],[3,0],[4,0],[4,0],]],
    [[11,2], [[4,0],[4,0],[1,0],[4,0],[4,0],[1,0],[4,0],[4,0],[1,0],]],
    
    [[0,3], [[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],]],
    [[1,3], [[0,0],[2,0],[2,0],[0,0],[2,0],[2,0],[0,0],[2,0],[2,0],]],
    [[2,3], [[2,0],[2,0],[2,0],[2,0],[2,0],[2,0],[2,0],[2,0],[2,0],]],
    [[3,3], [[2,0],[2,0],[0,0],[2,0],[2,0],[0,0],[2,0],[2,0],[0,0],]],
    [[4,3], [[3,0],[3,0],[3,0],[4,0],[4,0],[3,0],[4,0],[4,0],[3,0],]],
    [[5,3], [[3,0],[4,0],[4,0],[2,0],[4,0],[4,0],[2,0],[2,0],[2,0],]],
    [[6,3], [[4,0],[4,0],[3,0],[4,0],[4,0],[2,0],[2,0],[2,0],[2,0],]],
    [[7,3], [[3,0],[3,0],[3,0],[3,0],[4,0],[4,0],[3,0],[4,0],[4,0],]],
    [[8,3], [[1,0],[4,0],[4,0],[0,0],[4,0],[4,0],[0,0],[0,0],[2,0],]],
    [[9,3], [[4,0],[4,0],[4,0],[4,0],[4,0],[4,0],[2,0],[2,0],[2,0],]],
    [[10,3], [[4,0],[4,0],[4,0],[4,0],[4,0],[4,0],[3,0],[3,0],[3,0],]],
    [[11,3], [[4,0],[4,0],[1,0],[4,0],[4,0],[0,0],[2,0],[0,0],[0,0],]],
];
// convert 4x4 to godot
var fourxfour_data = [
    [[0,0],[0,0]], [[1,0],[1,0]], [[2,0],[2,0]], [[3,0],[3,0]],
    [[0,1],[0,1]], [[1,1],[1,1]], [[2,1],[2,1]], [[3,1],[3,1]],
    [[0,2],[0,2]], [[1,2],[1,2]], [[2,2],[2,2]], [[3,2],[3,2]],
    [[0,3],[0,3]], [[1,3],[1,3]], [[2,3],[2,3]], [[3,3],[3,3]],
    
    [[4,0],[2,1]], [[5,0],[2,0]], [[6,0],[2,0]], [[7,0],[2,1]],
    [[4,1],[1,1]], [[5,1],[2,1]], [[6,1],[2,1]], [[7,1],[3,1]],
    [[4,2],[1,1]], [[5,2],[2,1]], [[6,2],[2,1]], [[7,2],[3,1]],
    [[4,3],[2,1]], [[5,3],[2,2]], [[6,3],[2,2]], [[7,3],[2,1]],
    
    [[8,0],[1,0]], [[9,0],[2,1]], [[10,0],[2,0]], [[11,0],[3,0]],
    [[8,1],[1,1]], [[9,1],[2,1]], [[10,1],[-1,-1]], [[11,1],[2,1]],
    [[8,2],[2,1]], [[9,2],[2,1]], [[10,2],[2,1]], [[11,2],[3,1]],
    [[8,3],[1,2]], [[9,3],[2,2]], [[10,3],[2,1]], [[11,3],[3,2]],
];
// convert 3x3 to 4x4
var threexthree_data = [
    [[0,0], [[0,0],[2,0],[2,0],[0,1],[2,1],[2,1],[0,1],[2,1],[2,1],]],
    [[1,0], [[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],]],
    [[2,0], [[1,0],[1,0],[1,0],[1,0],[1,0],[1,0],[1,0],[1,0],[1,0],]],
    [[3,0], [[2,0],[2,0],[2,0],[2,0],[2,0],[2,0],[2,0],[2,0],[2,0],]],

    [[0,1], [[0,1],[2,1],[2,1],[0,1],[2,1],[2,1],[0,1],[2,1],[2,1],]],
    [[1,1], [[0,1],[0,1],[0,1],[0,1],[0,1],[0,1],[0,1],[0,1],[0,1],]],
    [[2,1], [[1,1],[1,1],[1,1],[1,1],[1,1],[1,1],[1,1],[1,1],[1,1],]],
    [[3,1], [[2,1],[2,1],[2,1],[2,1],[2,1],[2,1],[2,1],[2,1],[2,1],]],

    [[0,2], [[0,1],[2,1],[2,1],[0,2],[2,2],[2,2],[0,2],[2,2],[2,2],]],
    [[1,2], [[0,2],[0,2],[0,2],[0,2],[0,2],[0,2],[0,2],[0,2],[0,2],]],
    [[2,2], [[1,2],[1,2],[1,2],[1,2],[1,2],[1,2],[1,2],[1,2],[1,2],]],
    [[3,2], [[2,2],[2,2],[2,2],[2,2],[2,2],[2,2],[2,2],[2,2],[2,2],]],

    [[0,3], [[0,0],[2,0],[2,0],[0,2],[2,2],[2,2],[0,2],[2,2],[2,2],]],
    [[1,3], [[0,0],[0,0],[0,0],[0,2],[0,2],[0,2],[0,2],[0,2],[0,2],]],
    [[2,3], [[1,0],[1,0],[1,0],[1,2],[1,2],[1,2],[1,2],[1,2],[1,2],]],
    [[3,3], [[2,0],[2,0],[2,0],[2,2],[2,2],[2,2],[2,2],[2,2],[2,2],]],
];
var inner_corners_data = [
    [[1,0], [[1,1]]],
    [[2,0], [[0,1], [1,1]]],
    [[3,0], [[0,1]]],
    
    [[1,1], [[1,1],[1,0]]],
    [[2,1], [[0,0],[0,1],[1,0],[1,1]]],
    [[3,1], [[0,0],[0,1]]],
    
    [[1,2], [[1,0]]],
    [[2,2], [[0,0],[1,0],]],
    [[3,2], [[0,0]]],
    
    
    [[4,0], [[0,1],[1,0],[1,1]]],
    [[5,0], [[0,1]]],
    [[6,0], [[1,1]]],
    [[7,0], [[0,1],[0,0],[1,1]]],
    
    [[4,1], [[1,0]]],
    [[5,1], [[0,0]]],
    [[6,1], [[1,0]]],
    [[7,1], [[0,0]]],
    
    [[4,2], [[1,1]]],
    [[5,2], [[0,1]]],
    [[6,2], [[1,1]]],
    [[7,2], [[0,1]]],
    
    [[4,3], [[0,0],[1,0],[1,1]]],
    [[5,3], [[0,0]]],
    [[6,3], [[1,0]]],
    [[7,3], [[0,1],[0,0],[1,0]]],
    
    [[9,0], [[0,0],[1,0]]],
    [[11,1], [[1,0],[1,1]]],
    [[8,2], [[0,0],[0,1]]],
    [[10,3], [[0,1],[1,1]]],
    
    [[9,1], [[0,0],[1,1]]],
    [[10,2], [[1,0],[0,1]]],
];
// convert godot to preview
let x = -1;
var preview_data = [
    [x,x,0],
    [x,36,14,38,x,x,x,x,x,0],
    [x,x,23,x,x,x,x,x,x,16,11],
    [x,x,x,x,35,x,36,37,5,17,22,38],
    [8,11,x,x,x,x,x,x,43,45,46],
    [20,34,x,0,x,x,x,x,x,23],
    [20,18,10,9,11,x,8,11],
    [20,32,32,32,34,x,43,33,11],
    [43,44,44,44,46,x,x,43,46]
];
var godot_to_gms = [
    43, 36, 24, 38, 15, 23, 22, 14, 35,  4, 21, 37,
    33, 20, 16, 28, 18,  2,  3, 27, 17,  6, -1,  7,
    45, 42, 32, 40, 19,  9,  5, 26, 10,  1, 11, 25,
    47, 44, 34, 46,  8, 30, 31, 12, 41, 29, 13, 39
];
</script>
</body>
</html>
